package com.topcent.tioxyc.controller;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.topcent.tioxyc.constants.KeyConstant;
import com.topcent.tioxyc.mapper.PurchaseOrderListMapper;
import com.topcent.tioxyc.mapper.SalesGrossProfitDataMapper;
import com.topcent.tioxyc.mapper.Yy1KpiMapper;
import com.topcent.tioxyc.pojo.*;
import com.topcent.tioxyc.pojo.cc.OrderDeliveryRateCC;
import com.topcent.tioxyc.pojo.cc.TransferOrderCC;
import com.topcent.tioxyc.pojo.vo.*;
import com.topcent.tioxyc.service.PurchaseOrderListService;
import com.topcent.tioxyc.service.SalesGrossProfitDataService;
import com.topcent.tioxyc.util.ApiClient;
import com.topcent.tioxyc.util.ConnmeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.ParseException;
import org.apache.http.message.BasicHeader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

/**
 * @author: 陈百万
 * @date: 2025/3/31 11:40  @GetMapping("salesDataOfAnalysisTotal")
 * @Description: 陈百万Controller 销售-交货全部数据
 */
@Slf4j
@RestController
public class CcSalesGrossProfitDataTotalController {
    @Autowired
    private Yy1KpiMapper yy1KpiMapper;
    /**
     * 销售订单-交货数据分析【全部】计算
     * @return
     */
    @GetMapping("salesDataOfAnalysisTotal")
    public String salesDataOfAnalysisTotal() {
        Header[] headers = ConnmeUtils.createHeaders();
        String appId = "67f8aa2676b9b3942c49035f";
        // "formName": "销售订单-交货数据分析全部"
        String entryId = "68fae026d12c1eb2a5a17434";

        // 获取检验通知单数据
        List<InspectionNoticeVO> inspectionNoticeList = getInspectionNoticeList();
        Map<String, Date> dateMap = processInspectionNoticeToDateMap(inspectionNoticeList);

        // 获取sap采购申请api数据
        Header[] sapHeaders = new Header[3];
        String auth = KeyConstant.sapSALE001APIName + ":" + KeyConstant.sapSALE001APIPass;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
        String authHeader = "Basic " + encodedAuth;
        sapHeaders[0] = new BasicHeader("Accept", "application/json");
        sapHeaders[1] = new BasicHeader("Authorization", authHeader);
        sapHeaders[2] = new BasicHeader("x-csrf-token", "Fetch");
        JSONObject entries =
                ApiClient.sendGetRequest("https://my200654-api.s4hana.sapcloud.cn/sap/opu/odata/sap/YY1_PURREQUISITIONITEM_API_CDS/YY1_PurRequisitionItem_API", sapHeaders, null);
        String d = entries.getStr("d");
        JSONObject sapObjects = JSONUtil.parseObj(d);
        String results = sapObjects.getStr("results");
        JSONArray objectss = JSONUtil.parseArray(results);
        List<PurchaseRequisitionSAPVO> purchaseRequisitionSAPVOList = JSONUtil.toList(objectss, PurchaseRequisitionSAPVO.class);
        // 同时处理两个日期字段的赋值
        purchaseRequisitionSAPVOList.forEach(vo -> {
                    // 处理创建日期
                    vo.setCreationDate(parseSapDate(vo.getPurchaseReqnCreationDate()));
                    // 处理审批日期
                    vo.setReleaseDate(parseSapDate(vo.getPurchaseRequisitionReleaseDate()));
                });
        // 构建映射：(销售单号+销售行项目+物料号) → 对应的PurchaseRequisitionSAPVO对象
        Map<String, PurchaseRequisitionSAPVO> sapPurchaseRequisitionDataMap = purchaseRequisitionSAPVOList.stream()
                .collect(Collectors.toMap(
                        // 生成键：组合三个字段
                        vo -> generateKey(vo.getSDDocument(), vo.getSalesDocumentItem(), vo.getMaterial()),
                        // 值：直接使用当前对象
                        vo -> vo,
                        // 重复键处理：保留第一个出现的对象
                        (existing, replacement) -> existing
                ));

        // 获取用户人员信息
        Map<String ,Object> person =new HashMap<>();
        person.put("dept_no", 1);
        person.put("has_child", true);
        JSONObject personResult = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/corp/department/user/list", headers, JSONUtil.toJsonStr(person));
        String personData = personResult.getStr("users");
        JSONArray personObjects = JSONUtil.parseArray(personData);
        List<Assignee> personList = JSONUtil.toList(personObjects, Assignee.class);

        // 获取销售部门信息
        Map<String ,Object> cond =new HashMap<>();
        cond.put("dept_no", 1);
        cond.put("has_child", true);
        JSONObject deptResult = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/corp/department/list", headers, JSONUtil.toJsonStr(cond));
        String data = deptResult.getStr("departments");
        JSONArray objects = JSONUtil.parseArray(data);
        List<DepartmentVO> deptList = JSONUtil.toList(objects, DepartmentVO.class);

        //批量删除简道云数据
        selectAndList(headers, appId, entryId);

        Map<String, String> userNameMap = personList.stream()
                .collect(Collectors.toMap(Assignee::getName, Assignee::getUsername, (v1, v2) -> v1));

        Map<String, Integer> deptMap = deptList.stream()
                .collect(Collectors.toMap(DepartmentVO::getName, DepartmentVO::getDept_no, (v1, v2) -> v1));

        // 只调用一次查询简道云销售订单数据方法
        List<SalesOrder> salesOrderList = this.getSalesOrderList();

        // 获取最早审核日期
        Map<String, DateTime> salesDocMinDateMap = salesOrderList.stream()
                .filter(so -> so.getReview_date() != null) // 过滤空日期
                .collect(Collectors.toMap(
                        SalesOrder::get_widget_1718759603973, // 键：销售单号
                        SalesOrder::getReview_date,   // 值：日期
                        BinaryOperator.minBy(Comparator.naturalOrder()) // 冲突时保留较小的日期
                ));

        // 获取是否出库 true
        Map<String, String> salesDocLatestStockOutMap = salesOrderList.stream()
                .filter(so -> so.getCreateTime() != null)
                .collect(Collectors.toMap(
                        SalesOrder::get_widget_1718759603973,
                        so -> new AbstractMap.SimpleEntry<>(so.getCreateTime(), so.get_widget_1730952275092()),
                        // 先保留时间和值的映射，合并时比较时间
                        (entry1, entry2) -> entry1.getKey().isAfter(entry2.getKey()) ? entry1 : entry2
                ))
                // 最后提取值（是否出库存）
                .entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().getValue()
                ));

        // 新增：获取最新创建数据的整单交货日期
        // 用Optional包装，显式标记可能为空
        Map<String, Optional<DateTime>> salesDocLatestDeliveryDateMap = salesOrderList.stream()
                .filter(so -> so.getCreateTime() != null && so.get_widget_1718759603973() != null)
                .collect(Collectors.toMap(
                        SalesOrder::get_widget_1718759603973,
                        so -> new AbstractMap.SimpleEntry<>(so.getCreateTime(), so.get_widget_1718759603988()),
                        (entry1, entry2) -> entry1.getKey().isAfter(entry2.getKey()) ? entry1 : entry2,
                        HashMap::new
                ))
                .entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> Optional.ofNullable(entry.getValue().getValue()), // 用Optional包装null
                        (v1, v2) -> v1,
                        HashMap::new
                ));
        //客户建档日期
        Map<String, Date> customerList = getCustomerList();

        //销售表数据
        List<YY1_KPI> yy1KpiList = yy1KpiMapper.selectAll();
        // 定义需要排除的销售订单号
        List<String> excludeSales = Arrays.asList("2000000383",
                "2000005882",
                "2000006099",
                "2000006443",
                "2000006437",
                "2000006450",
                "2000006451",
                "2000006452",
                "2000006435");
        // 过滤掉这些订单号的数据（保留其他所有数据）
        yy1KpiList = yy1KpiList.stream()
                .filter(kpi -> !excludeSales.contains(kpi.getSalesDocument())) // 核心：排除目标订单号
                .collect(Collectors.toList()); // 返回可修改的ArrayList

        List<YY1_KPI> yy1KpiListNew = new ArrayList<>();

        String dateTime = "1949-06-01 00:00:00";
        DateTime DATE_THRESHOLD = new DateTime(dateTime);
        // 遍历销售数据列表
        for (YY1_KPI kpi : yy1KpiList) {
            String salesDocument = kpi.getSalesDocument(); // 获取销售订单号

            // 通过订单号获取最早审核时间
            DateTime minApprovalTime = salesDocMinDateMap.get(salesDocument);

            // 判断时间是否存在且大于等于2025年6月1日
            if (minApprovalTime != null && !minApprovalTime.isBefore(DATE_THRESHOLD)) {
                kpi.setYY1_lastapptime_SDHS(minApprovalTime); // 赋值给对象
                yy1KpiListNew.add(kpi);
            }
        }

        // 1. 先按销售单号分组（保留所有组的原始数据）
        Map<String, List<YY1_KPI>> groupBySalesDoc = yy1KpiListNew.stream()
                .filter(kpi -> kpi.getSalesDocument() != null && !kpi.getSalesDocument().trim().isEmpty())
                .collect(Collectors.groupingBy(YY1_KPI::getSalesDocument));

        // 2. 筛选出总和>5000的组，保留原始数据
        Map<String, List<YY1_KPI>> resultMap = new HashMap<>();

        for (Map.Entry<String, List<YY1_KPI>> entry : groupBySalesDoc.entrySet()) {
            String salesDoc = entry.getKey(); // 销售单号
            List<YY1_KPI> kpiList = entry.getValue(); // 该组的所有数据

            // 计算当前组的ConditionAmount总和
            BigDecimal total = kpiList.stream()
                    .map(kpi -> kpi.getConditionAmount() != null ? kpi.getConditionAmount() : BigDecimal.ZERO)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 筛选总和>5000的组
            if (total.compareTo(new BigDecimal("0")) > 0) {
                resultMap.put(salesDoc, kpiList); // 保留该组的原始数据
            }
        }
        // 获取交货表数据
        List<DeliveryDocumentsEntity> originalData = yy1KpiMapper.selectDeliveryDocumentsDateIsNotNull();

        // 获取采购订单原始数据
        List<PurchaseOrderList> originalProductData = yy1KpiMapper.selectPurchaseOrderAll();

        //构建交货单索引（用于快速匹配）
        Map<String, List<DeliveryDocumentsEntity>> deliveryIndex = originalData.stream()
                .filter(delivery -> delivery.getReferenceSDDocument() != null &&
                        delivery.getReferenceSDDocumentItem() != null)
                .collect(Collectors.groupingBy(
                        delivery -> delivery.getReferenceSDDocument() + "_" + delivery.getReferenceSDDocumentItem()
                ));

        // 采购订单
        // 构建映射：(销售单号+销售行项目+物料号) → 对应的PurchaseOrderList对象
        Map<String, PurchaseOrderList> productIndex = originalProductData.stream()
                .collect(Collectors.toMap(
                        // 生成键：组合三个字段
                        vo -> generateKey(vo.getSalesOrder(), vo.getSalesOrderItem(), vo.getMaterial()),
                        // 值：直接使用当前对象
                        vo -> vo,
                        // 重复键处理：保留第一个出现的对象
                        (existing, replacement) -> existing
                ));


        // 遍历每个销售单组，匹配交货状态
        for (List<YY1_KPI> kpiList : resultMap.values()) {
            // 统计组内状态
            int fullyDeliveredCount = 0;
            int partiallyDeliveredCount = 0;
            int notDeliveredCount = 0;
            Date latestDeliveryDate = null;

            // 遍历组内每条销售单行
            for (YY1_KPI kpi : kpiList) {
                String key = kpi.getSalesDocument() + "_" + kpi.getSalesDocumentItem();
                List<DeliveryDocumentsEntity> deliveries = deliveryIndex.getOrDefault(key, Collections.emptyList());
                // 交货数量
                int totalDeliveryQuantity = deliveries.stream()
                        .mapToInt(DeliveryDocumentsEntity::getActualDeliveryQuantity)
                        .sum();
                kpi.setDeliveryNum(totalDeliveryQuantity);
                kpi.setDeliveryNo(CollectionUtils.isEmpty(deliveries) ? null : deliveries.getFirst().getDeliveryDocument());
                kpi.setDeliveryMoney(CollectionUtils.isEmpty(deliveries) ? null : deliveries.getFirst().getAmount2());
                if (deliveries.isEmpty()) {
                    // 未找到对应交货单
                    kpi.set_widget_1752125855356("未出货");
                    notDeliveredCount++;
                } else {
                    // 找到对应交货单，检查数量是否一致
                    int salesQuantity = kpi.getQuantity();
                    if (salesQuantity == totalDeliveryQuantity) {
                        // 数量完全匹配
                        kpi.set_widget_1752125855356("全部出货");
                        fullyDeliveredCount++;
                    } else {
                        // 数量不匹配
                        kpi.set_widget_1752125855356("部分出货");
                        partiallyDeliveredCount++;
                    }

                    // 查找最晚交货日期：先过滤null，再求最大值
                    Date currentLatestDate = deliveries.stream()
                            .map(DeliveryDocumentsEntity::getActualGoodsMovementDate) // 提取日期
                            .filter(Objects::nonNull) // 关键：过滤掉null的日期
                            .max(Date::compareTo) // 此时流中无null，可安全比较
                            .orElse(null); // 如果过滤后流为空，返回null

                    if (currentLatestDate != null &&
                            (latestDeliveryDate == null || currentLatestDate.after(latestDeliveryDate))) {
                        latestDeliveryDate = currentLatestDate;
                    }
                }
            }
            // 设置组整体交货状态
            String groupStatus;
            if (fullyDeliveredCount == kpiList.size()) {
                groupStatus = "全部出货";
            } else if (notDeliveredCount == kpiList.size()) {
                groupStatus = "未出货";
            } else {
                groupStatus = "部分出货";
            }

            // 为组内每条记录设置整体状态和最晚交货日期
            for (YY1_KPI kpi : kpiList) {
                kpi.set_widget_1752125855357(groupStatus);
                kpi.set_widget_1752128631870(latestDeliveryDate);
            }
        }

        List<Map<String, Object>> mapList = new ArrayList<>();
        // 遍历resultMap中的所有KPI记录（已处理过交货状态）
        for (List<YY1_KPI> kpiList : resultMap.values()) {
            for (YY1_KPI yy1Kpi : kpiList) {
                SalesDataAnalysis vo = new SalesDataAnalysis();
                //采购申请信息
                PurchaseRequisitionSAPVO purchaseRequisitionSAPVO = sapPurchaseRequisitionDataMap.get(
                        generateKey(yy1Kpi.getSalesDocument(), yy1Kpi.getSalesDocumentItem(), yy1Kpi.getMaterial()));
                if(ObjectUtils.isNotEmpty(purchaseRequisitionSAPVO)){
                    // 设置字段值
                    vo.set_widget_1753423798924(purchaseRequisitionSAPVO.getRequestedQuantity());
                    vo.set_widget_1753423798925(purchaseRequisitionSAPVO.getCreationDate());
                    vo.set_widget_1753423798926(purchaseRequisitionSAPVO.getReleaseDate());
                }

                // 采购订单
                PurchaseOrderList purchaseOrderList = productIndex.get(
                        generateKey(yy1Kpi.getSalesDocument(), yy1Kpi.getSalesDocumentItem(), yy1Kpi.getMaterial()));

                if(ObjectUtils.isNotEmpty(purchaseOrderList)){
                    // 设置字段值
                    // 采购订单日期
                    vo.set_widget_1756707938600(parseDate(purchaseOrderList.getPurchaseOrderDate()));
                    // 采购订单数量
                    vo.set_widget_1756707938601(Integer.valueOf(purchaseOrderList.getOrderQuantity()));
                    // 采购订单行金额 物料净值
                    String amountStr = purchaseOrderList.getNetAmount();
                    BigDecimal amount = (amountStr == null || amountStr.trim().isEmpty())
                            ? BigDecimal.ZERO  // 空值默认0
                            : new BigDecimal(amountStr.trim());
                    vo.set_widget_1762235984129(amount);
                }

                // 供方完工日期
                vo.set_widget_1753750960203(dateMap.get(generateKey(yy1Kpi.getSalesDocument(), yy1Kpi.getSalesDocumentItem(), yy1Kpi.getMaterial())));

                vo.set_widget_1753423798927(yy1Kpi.getYY1_Brand_SDI() ? "是" : "否");

                vo.set_widget_1743998205163(getYearMonth(yy1Kpi.getYY1_lastapptime_SDH()));
                vo.set_widget_1743997558327(yy1Kpi.getSalesDocument());
                vo.set_widget_1744784769246(yy1Kpi.getSalesDocument());
                vo.set_widget_1743997558328(yy1Kpi.getSalesDocumentItem());
                vo.set_widget_1743997558329(yy1Kpi.getSoldToParty());
                vo.set_widget_1743997558330(yy1Kpi.getCustomerName());
                vo.set_widget_1743997558331(yy1Kpi.getBusinessPartnerName1());
                vo.set_widget_1744099905120(yy1Kpi.getAuthorizationGroupText());
                vo.set_widget_1751677806926(yy1Kpi.getAuthorizationGroupText());
                vo.set_widget_1743997558333(yy1Kpi.getCompanyCodeName());
                vo.set_widget_1743997558335(yy1Kpi.getPurchaseOrderByCustomer());
                vo.set_widget_1743997558336(yy1Kpi.getMaterial());
                vo.set_widget_1743997558337(yy1Kpi.getSalesDocumentItemText());
                vo.set_widget_1743997558338(yy1Kpi.getQuantity());
                vo.set_widget_1743997558339(yy1Kpi.getNetAmount());
                vo.set_widget_1743997558340(yy1Kpi.getOrderQuantityUnit());
                vo.set_widget_1743997558341(yy1Kpi.getConditionAmount());
                vo.set_widget_1743997558342(yy1Kpi.getExchangeRate_a());
                vo.set_widget_1743997558343(yy1Kpi.getGroupCurrency());
                vo.set_widget_1743997558344(convertToISO8601Format(yy1Kpi.getYY1_lachangedatetime1_SDH()));
                vo.set_widget_1743997558345(yy1Kpi.getID());
                vo.set_widget_1743997558346(yy1Kpi.getSalesDocApprovalStatusDesc());
                vo.set_widget_1743997558347(yy1Kpi.getAddressSearchTerm2());
                vo.set_widget_1743997558348(convertToISO8601Format(yy1Kpi.getCreationDate()));
                vo.set_widget_1743997558349(yy1Kpi.getOverallTotalDeliveryStatus());
                vo.set_widget_1743997558350(yy1Kpi.getOverallDeliveryStatus());
                vo.set_widget_1743997558351(yy1Kpi.getPlant());
                vo.set_widget_1743997558352(yy1Kpi.getCurrency());
                vo.set_widget_1743997558353(yy1Kpi.getExchangeRate_b());
                vo.set_widget_1743997558354(yy1Kpi.getNetAmount_1());
                vo.set_widget_1743997558355(yy1Kpi.getConditionAmount1());
                vo.set_widget_1743997558356(yy1Kpi.getConditionCurrency());

                vo.set_widget_1743997558357(yy1Kpi.getGsjing());
                vo.set_widget_1743997558358(yy1Kpi.getGshan());
                vo.set_widget_1743997558359(convertToISO8601Format(yy1Kpi.getYY1_lastapptime_SDH()));
                vo.set_widget_1743997558360(yy1Kpi.getYY1_ZBMCL_SD_SDI());
                vo.set_widget_1743997558361(yy1Kpi.getYY1_ZCL_SD_SDI());
                vo.set_widget_1743997558362(yy1Kpi.getYY1_ZGGCC_SD_SDI());
                vo.set_widget_1743997558363(yy1Kpi.getYY1_ZBZXX_SD_SDI());
                vo.set_widget_1743997558364(yy1Kpi.getYY1_KS_SD_SDI());
                vo.set_widget_1743997558365(yy1Kpi.getYY1_ZCPJZ_SD_SDI());
                vo.set_widget_1743997558366(yy1Kpi.getYY1_ZPJ_SD_SDI());
                vo.set_widget_1743997558367(yy1Kpi.getVCDescription());
                vo.set_widget_1743997558368(yy1Kpi.getYY1_BGPM_PRD());
                vo.set_widget_1743997558369(yy1Kpi.getYY1_Brand_SDI());
                vo.set_widget_1743997558370(yy1Kpi.getCountryName());
                vo.set_widget_1743997558371(yy1Kpi.getYY1_khly_bus());
                vo.set_widget_1743997558372(yy1Kpi.getBusinessPartnerGroupingText());
                vo.set_widget_1743997558373(convertToISO8601Format(yy1Kpi.getRequestedDeliveryDate()));
                vo.set_widget_1761552134417(yy1Kpi.getDeliveryMoney());

                vo.set_widget_1749538106589(yy1Kpi.getYY1_lastapptime_SDHS());// 最早审核时间
                vo.set_widget_1749628279931(customerList.get(yy1Kpi.getSoldToParty()));//客户建档日期

                if(StringUtils.isNotBlank(yy1Kpi.getSalesOfficeName()) && yy1Kpi.getSalesOfficeName().contains("中非销售")){
                yy1Kpi.setSalesOfficeName("BCP中非销售部");
                }else if(StringUtils.isNotBlank(yy1Kpi.getSalesOfficeName()) && yy1Kpi.getSalesOfficeName().contains("东南亚销售")){
                yy1Kpi.setSalesOfficeName("BCP东南亚销售部");
                }else if(StringUtils.isNotBlank(yy1Kpi.getSalesOfficeName()) && yy1Kpi.getSalesOfficeName().contains("DIY销售部")){
                yy1Kpi.setSalesOfficeName("BCP美澳销售部");
                }else if(StringUtils.isNotBlank(yy1Kpi.getSalesOfficeName()) && yy1Kpi.getSalesOfficeName().contains("PRO国内销售部")){
                    yy1Kpi.setSalesOfficeName("PRO亚非销售部");
                }

                vo.set_widget_1752125855356(yy1Kpi.get_widget_1752125855356());
                vo.set_widget_1752125855357(yy1Kpi.get_widget_1752125855357());
                vo.set_widget_1752128631870(yy1Kpi.get_widget_1752128631870());
                vo.set_widget_1752128631871(yy1Kpi.getDeliveryNum());
                vo.set_widget_1752128631872(countTime(vo.get_widget_1752128631870(), vo.get_widget_1749538106589()));
                vo.set_widget_1752560851698(yy1Kpi.getDeliveryNo());

                String sName = yy1Kpi.getSalesOfficeName();
                vo.set_widget_1751677806927(sName);

                String username = userNameMap.get(vo.get_widget_1744099905120());
                if(("刘晓琪").equals(vo.get_widget_1744099905120())){
                    username = "woxjrqDwAAUDe1Gd9cSVXI5sfRaqZ9jQ";
                }
                if (username != null) {
                    vo.set_widget_1744099905120(username);
                }

                Integer deptNo = deptMap.get(sName);
                if (deptNo != null) {
                    vo.set_widget_1744094850882(deptNo);
                }

                vo.set_widget_1753265368863("true".equals(salesDocLatestStockOutMap.get(yy1Kpi.getSalesDocument())) ? "是" : "否");
                vo.set_widget_1761644729260(salesDocLatestDeliveryDateMap.get(yy1Kpi.getSalesDocument()).orElse(null));

                vo.set_id(null);
                mapList.add(ConnmeUtils.convertEntityToMap(vo));
            }
        }
        log.info("销售订单数据mapList：==== {}", mapList.size());
        // 批量存入简道云
        ConnmeUtils.batchAddList(headers, appId, entryId, mapList);
        /*// 销售订单-交货数据-来货检验状态
        salesDataOfInspectionAnalys();*/
        return "数据插入成功：" + mapList.size();
    }

    public String countTime(Date a, Date b) {
        if (a == null || b == null) {
            return "";
        }

        // +8 小时偏移
        DateTime d1 = DateUtil.offsetHour(DateUtil.date(a), 8);
        DateTime d2 = DateUtil.offsetHour(DateUtil.date(b), 8);

        long days = DateUtil.between(d1, d2, DateUnit.DAY);
        if(d1.isBefore(d2) && days > 0){
            return "-" + days;
        }
        return String.valueOf(days);
    }


    /**
     * 销售订单-交货数据-来货检验状态【备用刷新全部数据】
     * @return
     */
    @GetMapping("newSalesDataOfData")
    public String salesDataOfInspectionAnalys() {
        long startTime = System.currentTimeMillis();
        Header[] headers = ConnmeUtils.createHeaders();
        /*int concurrentSize = 19; // 适配简道云v5接口20次/秒频率
        ThreadPoolTaskExecutor executor = createThreadPool(concurrentSize);*/

        // 1. 获取四种表单数据
        List<InspectedVO> salesDataList = fetchJianDaoYunData(
                headers, "67f8aa2676b9b3942c49035f", "68fae026d12c1eb2a5a17434", InspectedVO.class
        );

        List<ZPurchaseOrderList> purchaseDataList = fetchJianDaoYunData(
                headers, "67f8aa2676b9b3942c49035f", "67ff675568c6ea7be7efebe9", ZPurchaseOrderList.class
        );

        List<InspectionData> inspectionDataList = fetchJianDaoYunData(
                headers, "64a7b7416bbd930007630ed5", "64a7b81afc35ba00082dbcad", InspectionData.class
        );

        // 调拨单
        List<TransferOrderCC> transferOrderCCList = fetchJianDaoYunData(
                headers, "66b036d584791562cc5c5873", "66b036da08e614321a19b90f", TransferOrderCC.class
        );

        // 4. 处理调拨单数据：分离子表单，按唯一键合并（直接用sonInfo存储）
        Map<String, TransferOrderCC.sonInfo> transferIndex = new HashMap<>();

        for (TransferOrderCC transfer : transferOrderCCList) {
            // 获取父表单的创建时间（用于覆盖子表单的createTime）
            Date outerCreateTime = transfer.getCreateTime();
            // 获取子表单列表（避免空指针）
            List<TransferOrderCC.sonInfo> sonInfos = transfer.get_widget_1722824410152();
            if (sonInfos == null || sonInfos.isEmpty()) {
                continue;
            }

            for (TransferOrderCC.sonInfo son : sonInfos) {
                // 提取三个唯一键字段（处理空值）
                String orderNo = Optional.ofNullable(son.get_widget_1724144567539()).orElse("");
                String lineNo = Optional.ofNullable(son.get_widget_1724144567540()).orElse("");
                String productCode = Optional.ofNullable(son.get_widget_1722825130187()).orElse("");
                String key = generateKey(orderNo, padWithZeros6(lineNo), productCode); // 复用生成键的方法

                // 提取当前子表单的数量（空值按0处理）
                Double currentQty = Optional.ofNullable(son.get_widget_1722825130197()).orElse(0.0);

                // 合并逻辑
                if (transferIndex.containsKey(key)) {
                    // 已存在：累加数量
                    TransferOrderCC.sonInfo existing = transferIndex.get(key);
                    existing.set_widget_1722825130197(existing.get_widget_1722825130197() + currentQty);
                } else {
                    // 不存在：新建sonInfo，用父表单的创建时间
                    TransferOrderCC.sonInfo newSon = new TransferOrderCC.sonInfo();
                    newSon.set_widget_1724144567539(orderNo); // 订单号
                    newSon.set_widget_1724144567540(lineNo); // 行号
                    newSon.set_widget_1722825130187(productCode); // 产品编码
                    newSon.set_widget_1722825130197(currentQty); // 初始数量
                    newSon.setCreateTime(outerCreateTime); // 用父表单的创建时间
                    transferIndex.put(key, newSon);
                }
            }
        }

        log.info("调拨单合并完成，共{}条合并数据", transferIndex.size());

        log.info("获取数据完成：销售{}条，采购{}条，检验{}条",
                salesDataList.size(), purchaseDataList.size(), inspectionDataList.size());
        // 2. 构建采购订单索引（销售订单号+行号+物料号 → 采购单信息）
        Map<String, ZPurchaseOrderList> purchaseIndex = purchaseDataList.stream()
                .collect(Collectors.toMap(
                        po -> generateKey(po.get_widget_1744791381554(), po.get_widget_1744791381555(), po.get_widget_1744791381526()),
                        po -> po,
                        (existing, replacement) -> existing // 重复键处理：保留第一个
                ));

        // 3. 构建检验结果索引（采购单号+行号+物料号 → 检验结果）
        Map<String, InspectionData> inspectionIndex = inspectionDataList.stream()
                .collect(Collectors.toMap(
                        insp -> generateKey(insp.getPurchasing_no(), padWithZeros(insp.getPurchasing_hang()), insp.getItem_no()),
                        insp -> insp,
                        (existing, replacement) -> existing // 重复键处理：保留第一个
                ));

        // 4. 处理数据（完全复现原逻辑：逐个处理每行数据）
        List<InspectedVO> needUpdateList = new ArrayList<>();
        for (InspectedVO salesData : salesDataList) {
            // 按销售订单号+行号分组销售订单行
            Map<String, List<InspectedVO>> salesLinesByOrder = salesDataList.stream()
                    .filter(line -> line.get_widget_1743997558327().equals(salesData.get_widget_1743997558327()))
                    .collect(Collectors.groupingBy(InspectedVO::get_widget_1743997558327));

            // 处理每个销售订单行
            for (Map.Entry<String, List<InspectedVO>> entry : salesLinesByOrder.entrySet()) {
                String salesLineNo = entry.getKey();
                List<InspectedVO> lines = entry.getValue();

                for (InspectedVO line : lines) {
                    // 生成销售订单行的唯一键
                    String salesKey = generateKey(
                            line.get_widget_1743997558327(),
                            line.get_widget_1743997558328(),
                            line.get_widget_1743997558336()
                    );

                    // ===== 新增：查询调拨单数据 =====
                    TransferOrderCC.sonInfo transferData = transferIndex.get(salesKey);
                    Double transferQty = transferData != null ? transferData.get_widget_1722825130197() : 0.0; // 调拨数量
                    Date transferTime = transferData != null ? transferData.getCreateTime() : null;
                    line.set_widget_1762246635678(transferQty.toString()); // 赋值调拨数量

                    // 获取对应的采购订单信息
                    ZPurchaseOrderList purchaseOrder = purchaseIndex.get(salesKey);

                    if (purchaseOrder != null) {
                        // 生成采购订单的唯一键
                        String purchaseKey = generateKey(
                                purchaseOrder.get_widget_1744791381513(),
                                purchaseOrder.get_widget_1744791381514(),
                                purchaseOrder.get_widget_1744791381526()
                        );

                        // 获取对应的检验结果
                        InspectionData inspectionData = inspectionIndex.get(purchaseKey);

                        if (inspectionData != null) {
                            // 赋值检验数量
                            line.set_widget_1762246635677(inspectionData.getTotal_qty() + "");
                            line.set_widget_1761791177269(inspectionData.getSupplier_name()); // 供方名称
                            line.set_widget_1761791177270(extractNameFromJson(inspectionData.get_widget_1692062631335())); // 采购员
                            // 设置行检验状态
                            String inspectionResult = inspectionData.getInspection_result();
                            line.set_widget_1752480273251("NG".equals(inspectionResult) ? "未检验" : "已检验");
                            // 设置行最后检验时间
                            if (line.get_widget_1752480273251().equals("已检验")) {
                                line.set_widget_1752480273253(parseDate(inspectionData.getDate_of_inspection()));
                            }
                        } else {
                            // 没有找到检验结果
                            line.set_widget_1752480273251("未检验");
                        }
                    } else {
                        // 没有找到对应的采购订单
                        line.set_widget_1752480273251("未检验");
                    }
                }
            }

            // 5. 计算销售订单整体检验状态
            calculateOverallStatus(salesData, salesLinesByOrder, transferIndex);
            // 收集当前salesData（与原逻辑一致：逐个更新每行数据）
            needUpdateList.add(salesData);

        }

        log.info("待更新数据量：{}条", needUpdateList.size());

        // 5. 并发更新（保留效率优化，不改变更新对象）
        if (!needUpdateList.isEmpty()) {
            for(InspectedVO line : needUpdateList){
                singleUpdateJianDaoYun(headers, line);
            }
            /*int batchSize = 10000;
            int totalSize = needUpdateList.size(); // 记录原始总大小（比如4万条，固定不变）
            int batchCount = (totalSize + batchSize - 1) / batchSize;
            List<String> failedIds = new CopyOnWriteArrayList<>();

            log.info("开始分批更新：共{}批，每批{}条，总数据{}条", batchCount, batchSize, totalSize);

            for (int batchNo = 0; batchNo < batchCount; batchNo++) {
                int startIdx = batchNo * batchSize;
                int endIdx = Math.min((batchNo + 1) * batchSize, totalSize); // 基于原始totalSize计算，不会超界

                // 关键修复：用new ArrayList()创建独立副本，完全脱离原列表
                List<InspectedVO> currentBatch = new ArrayList<>(
                        needUpdateList.subList(startIdx, endIdx) // 先取原列表片段，再转成新列表
                );
                int currentBatchSize = currentBatch.size();

                log.info("处理第{}批：数据范围[{}-{}]，共{}条", batchNo + 1, startIdx, endIdx - 1, currentBatchSize);

                CountDownLatch batchLatch = new CountDownLatch(currentBatchSize);

                for (InspectedVO line : currentBatch) {
                    executor.execute(() -> {
                        try {
                            singleUpdateJianDaoYun(headers, line);
                        } catch (Exception e) {
                            failedIds.add(line.get_id());
                        } finally {
                            batchLatch.countDown();
                        }
                    });
                }

                try {
                    boolean isBatchCompleted = batchLatch.await(60, TimeUnit.MINUTES);
                    if (!isBatchCompleted) {
                        log.error("第{}批更新超时！仍有{}条任务未完成", batchNo + 1, batchLatch.getCount());
                    }
                } catch (InterruptedException e) {
                    log.error("第{}批更新被中断", batchNo + 1, e);
                    Thread.currentThread().interrupt();
                    break;
                }

                // 现在clear的是副本，原列表完全不受影响
                currentBatch.clear();
                log.info("第{}批更新完成，累计失败{}条", batchNo + 1, failedIds.size());
            }

            log.info("所有批次更新结束：总提交{}条，失败{}条", totalSize, failedIds.size());
            if (!failedIds.isEmpty()) {
                log.error("更新失败的data_id列表：{}", failedIds);
            }*/
        }

        // 关闭线程池
        /*executor.shutdown();
        try {
            if (!executor.getThreadPoolExecutor().awaitTermination(30, TimeUnit.MINUTES)) {
                executor.getThreadPoolExecutor().shutdownNow();
                if (!executor.getThreadPoolExecutor().awaitTermination(10, TimeUnit.MINUTES)) {
                    log.error("线程池未能完全关闭");
                }
            }
        } catch (InterruptedException e) {
            executor.getThreadPoolExecutor().shutdownNow();
            Thread.currentThread().interrupt();
        }*/

        long endTime = System.currentTimeMillis();
        String result = String.format("处理完成，总耗时：%d分钟，更新数据%d条",
                (endTime - startTime) / 60000, needUpdateList.size());
        log.info(result);
        return result;
    }

    /**
     * 单条更新简道云（保留原接口参数和逻辑）
     */
    private void singleUpdateJianDaoYun(Header[] headers, InspectedVO line) {
        Map<String, Object> parameterInster = new HashMap<>();
        parameterInster.put("app_id", "67f8aa2676b9b3942c49035f");
        parameterInster.put("entry_id", "68fae026d12c1eb2a5a17434");
        parameterInster.put("is_start_trigger", "true");
        parameterInster.put("data_id", line.get_id());
        line.set_id(null);
        parameterInster.put("data", ConnmeUtils.convertEntityToMapNull(line));
        String jsonSalee = JSONUtil.toJsonStr(parameterInster);
        ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/app/entry/data/update", headers, jsonSalee);
    }

    /**
     * 创建线程池（适配高并发）
     */
    private ThreadPoolTaskExecutor createThreadPool(int coreSize) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(coreSize); // 保持19（适配20次/秒限流）
        executor.setMaxPoolSize(coreSize); // 最大线程=核心线程，避免创建过多线程触发限流
        executor.setQueueCapacity(30000); // 增大队列容量（根据你的最大数据量调整，比如1万条）
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("JianDaoYun-Update-");
        // 拒绝策略：阻塞直到队列有空间（不会丢弃任务）
        executor.setRejectedExecutionHandler((r, executor1) -> {
            try {
                // 无超时等待，直到队列有空间（避免任务丢失）
                executor1.getQueue().put(r);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("任务入队被中断", e);
            }
        });
        executor.initialize();
        return executor;
    }

    /**
     * 生成复合键（保留原有逻辑）
     */
    private String generateKey(String... parts) {
        return String.join("|", parts);
    }

    /**
     * 解析检验日期字符串为Date对象
     */
    private Date parseDate(String dateStr) {
        if (dateStr == null || dateStr.isEmpty()) {
            return null;
        }
        // 根据实际日期格式调整解析逻辑
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.parse(dateStr);
        } catch (ParseException e) {
            log.error("日期解析失败: {}", dateStr, e);
            return null;
        } catch (java.text.ParseException e) {
            throw new RuntimeException(e);
        }
    }

    // 完全复用原逻辑的calculateOverallStatus（仅更新传入的salesData，不同步其他行）
    private void calculateOverallStatus(InspectedVO salesData,
                                        Map<String, List<InspectedVO>> salesLinesByOrder,
                                        Map<String, TransferOrderCC.sonInfo> transferIndex) {

        Date requestDeliveryDate = salesData.get_widget_1761644729260(); // 要求整单交货日期
        List<String> allLineStatus = salesLinesByOrder.values().stream()
                .flatMap(List::stream)
                .map(InspectedVO::get_widget_1752480273251)
                .toList();

        long uninspectedCount = allLineStatus.stream().filter("未检验"::equals).count();
        long inspectedCount = allLineStatus.stream().filter("已检验"::equals).count();

        // ===== 新增：优先基于【整体交货状态】判断齐套与准时性 =====
        boolean isFullyMatched = true; // 齐套标记（默认齐套，交货状态不符合时再走数量校验）
        Date compareTime = null; // 用于对比的时间（优先用最晚交货时间，否则用检验/调拨时间）
        String overallDeliveryStatus = salesData.get_widget_1752125855357(); // 整体交货状态
        Date latestDeliveryTime = salesData.get_widget_1752128631870(); // 最晚交货时间

        // 1. 先判断整体交货状态：部分出货/全部出货 → 直接认定齐套，用最晚交货时间对比
        if ("部分出货".equals(overallDeliveryStatus) || "全部出货".equals(overallDeliveryStatus)) {
            isFullyMatched = true; // 交货状态符合 → 强制齐套
            compareTime = latestDeliveryTime; // 时间源切换为“最晚交货时间”
        }
        // 2. 交货状态不符合（如未出货/其他）→ 走原有数量校验+检验/调拨时间逻辑
        else {
            isFullyMatched = true; // 先默认齐套，数量不匹配再置为false
            compareTime = null;

            for (List<InspectedVO> lines : salesLinesByOrder.values()) {
                for (InspectedVO line : lines) {
                    // 解析销售数量、检验数量、调拨数量（处理空值+浮点数精度）
                    double salesQty = safeParseDouble(line.get_widget_1743997558338());
                    double inspectionQty = safeParseDouble(line.get_widget_1762246635677());
                    double transferQty = safeParseDouble(line.get_widget_1762246635678());

                    // 数量校验：销售数量 ≠ 检验+调拨数量 → 未齐套（浮点数精度容错）
                    if (Math.abs(salesQty - (inspectionQty + transferQty)) > 0.001) {
                        isFullyMatched = false;
                    }

                    // 时间校验：取检验时间/调拨时间的最大值
                    Date lineTime = null;
                    if (line.get_widget_1752480273253() != null) {
                        lineTime = line.get_widget_1752480273253();
                    } else {
                        // 从调拨索引中获取调拨时间
                        TransferOrderCC.sonInfo transferData = transferIndex.get(generateKey(
                                line.get_widget_1743997558327(),
                                line.get_widget_1743997558328(),
                                line.get_widget_1743997558336()
                        ));
                        if (transferData != null) {
                            lineTime = transferData.getCreateTime();
                        }
                    }

                    // 更新全局最晚时间
                    if (lineTime != null && (compareTime == null || lineTime.after(compareTime))) {
                        compareTime = lineTime;
                    }
                }
            }
        }

        // ===== 统一处理：齐套状态+准时性判定 =====
        String onTimeStatus = "未齐套";
        String delayDays = "0";

        if (isFullyMatched) { // 仅当齐套时，才判断准时性
            if (requestDeliveryDate != null && compareTime != null) {
                // 计算天数差（compareTime：优先最晚交货时间，其次检验/调拨时间）
                long timeDiffMs = compareTime.getTime() - requestDeliveryDate.getTime();
                long daysDiff = timeDiffMs / (1000 * 60 * 60 * 24);
                // 判定准时性：≤0 → 准时，>0 → 不准时
                onTimeStatus = daysDiff <= 0 ? "准时齐套" : "不准时齐套";
                delayDays = String.valueOf(daysDiff);
            } else {
                // 时间缺失（要求交货时间/对比时间为空）→ 无法判定，默认未齐套
                onTimeStatus = "未齐套";
            }
        } else {
            // 未齐套 → 无需判断准时性
            onTimeStatus = "未齐套";
        }

        // 赋值最终结果
        salesData.set_widget_1761791177267(onTimeStatus);
        salesData.set_widget_1761791177268(delayDays);

        // ===== 原有：整体检验状态赋值逻辑（保持不变） =====
        if (uninspectedCount == allLineStatus.size()) {
            salesData.set_widget_1752480273252("未检验");
            salesData.set_widget_1752480273254(null);
        } else if (inspectedCount == allLineStatus.size()) {
            salesData.set_widget_1752480273252("已检验");
            Date latestInspectionDate = salesLinesByOrder.values().stream()
                    .flatMap(List::stream)
                    .map(InspectedVO::get_widget_1752480273253)
                    .filter(Objects::nonNull)
                    .max(Date::compareTo)
                    .orElse(null);
            salesData.set_widget_1752480273254(latestInspectionDate);
        } else {
            salesData.set_widget_1752480273252("部分检验");
            Date latestInspectionDate = salesLinesByOrder.values().stream()
                    .flatMap(List::stream)
                    .filter(line -> "已检验".equals(line.get_widget_1752480273251()))
                    .map(InspectedVO::get_widget_1752480273253)
                    .filter(Objects::nonNull)
                    .max(Date::compareTo)
                    .orElse(null);
            salesData.set_widget_1752480273254(latestInspectionDate);
        }
    }

    // 新增：安全解析Double（处理空值、非数字，避免NumberFormatException）
    private double safeParseDouble(String value) {
        if (value == null || value.trim().isEmpty()) {
            return 0.0;
        }
        try {
            return Double.parseDouble(value.trim());
        } catch (NumberFormatException e) {
            log.warn("解析数字失败，值：{}，默认返回0.0", value);
            return 0.0;
        }
    }

    /**
     * 通用方法：从简道云分页获取表单数据（优化：移除System.out+批量日志）
     */
    private <T> List<T> fetchJianDaoYunData(Header[] headers, String appId, String entryId, Class<T> clazz) {
        List<T> resultList = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        params.put("app_id", appId);
        params.put("entry_id", entryId);
        boolean hasMore = true;
        String lastDataId = "";
        int pageNum = 1;

        do {
            if (!lastDataId.isEmpty()) {
                params.put("data_id", lastDataId);
            }
            params.put("limit", 100);

            String jsonParams = JSONUtil.toJsonStr(params);
            JSONObject response = ApiClient.sendPostRequest(
                    KeyConstant.Jian_URL + "/v5/app/entry/data/list",
                    headers,
                    jsonParams
            );

            String dataJson = response.getStr("data");
            JSONArray dataArray = JSONUtil.parseArray(dataJson);
            List<T> pageData = JSONUtil.toList(dataArray, clazz);

            if (pageData.size() == 100) {
                T lastData = pageData.get(pageData.size() - 1);
                lastDataId = getLastDataId(lastData);
            } else {
                hasMore = false;
            }

            resultList.addAll(pageData);
            // 替换System.out为日志，批量打印（减少IO消耗）
            if (pageNum % 10 == 0) { // 每10页打印一次
                log.info("简道云分页获取第{}页，累计数据量：{}", pageNum, resultList.size());
            }
            pageNum++;
        } while (hasMore);

        return resultList;
    }

    /**
     * 反射获取实体类的_id字段值（简道云数据默认有_id作为唯一标识）
     */
    private <T> String getLastDataId(T data) {
        try {
            // 假设实体类有get_id()方法
            Method method = data.getClass().getMethod("get_id");
            return (String) method.invoke(data);
        } catch (Exception e) {
            // 异常处理：若没有_id字段，返回空（终止分页）
            return "";
        }
    }

    /**
     * 将数字字符串补零至5位（如"10"→"00010"，"123"→"00123"）
     * @param numStr 原始数字字符串（如"10"、"20"）
     * @return 补零后的5位字符串
     */
    private String padWithZeros(String numStr) {
        if (numStr == null || numStr.trim().isEmpty()) {
            return "00000"; // 空值默认返回5个0（根据业务调整）
        }
        // 去除可能的空格，转换为数字后再格式化
        try {
            int num = Integer.parseInt(numStr.trim());
            // 格式化：%05d 表示5位数字，不足补0
            return String.format("%05d", num);
        } catch (NumberFormatException e) {
            // 非数字情况：返回原始值（或根据业务处理）
            //log.warn("采购行号不是数字：{}", numStr);
            return numStr;
        }
    }

    /**
     * 将数字字符串补零至6位（如"10"→"000010"，"123"→"000123"）
     * @param numStr 原始数字字符串（如"10"、"20"）
     * @return 补零后的6位字符串
     */
    private String padWithZeros6(String numStr) {
        if (numStr == null || numStr.trim().isEmpty()) {
            return "000000"; // 空值默认返回6个0（根据业务调整）
        }
        // 去除可能的空格，转换为数字后再格式化
        try {
            int num = Integer.parseInt(numStr.trim());
            // 格式化：%06d 表示6位数字，不足补0
            return String.format("%06d", num);
        } catch (NumberFormatException e) {
            // 非数字情况：返回原始值（或根据业务处理）
            //log.warn("采购行号不是数字：{}", numStr);
            return numStr;
        }
    }

    private DateTime parseSapDate(String sapDateStr) {
        if (StringUtils.isNotBlank(sapDateStr)) {
            long timestamp = Long.parseLong(ConnmeUtils.extractTimestamp(sapDateStr));
            LocalDateTime ldt = ConnmeUtils.convertTimestampToLocalDateTime(timestamp);
            return new DateTime(ConnmeUtils.formatDateTime(ldt), DatePattern.NORM_DATETIME_FORMAT);
        }
        return null;
    }

    // 获取检验通知单数据
    public List<InspectionNoticeVO> getInspectionNoticeList(){
        List<InspectionNoticeVO> inspectionNoticeVOList = new ArrayList<>();
        Header[] headers = ConnmeUtils.createHeaders();
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("app_id", "6690c7633df0f4b90b4ef551");
        parameter.put("entry_id", "66a734001584068c255b2fb2");

        Map<String, Object> filter = new HashMap<>();
        filter.put("rel", "and");
        Map<String, Object> cond = new HashMap<>();
        cond.put("field", "flowState");
        cond.put("type", "flowstate");
        cond.put("method", "eq");
        List<Integer> values = new ArrayList<>();
        values.add(1);
        cond.put("value", values);
        List<Map<String, Object>> conds = new ArrayList<>();
        conds.add(cond);
        filter.put("cond", conds);
        parameter.put("filter", filter);

        boolean fale = true;
        String zh = "";
        do {
            if (!zh.isEmpty()) {
                parameter.put("data_id", zh);
            }
            parameter.put("limit", 100);
            String jsonSale = JSONUtil.toJsonStr(parameter);
            JSONObject jdySale = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/app/entry/data/list", headers, jsonSale);
            String data = jdySale.getStr("data");
            JSONArray objects = JSONUtil.parseArray(data);
            List<InspectionNoticeVO> list = JSONUtil.toList(objects, InspectionNoticeVO.class);
            if (list.size() == 100) {
                zh = list.getLast().get_id();
            } else {
                fale = false;
            }
            inspectionNoticeVOList.addAll(list);
        } while (fale);
        return inspectionNoticeVOList;
    }



    public Map<String, Date> processInspectionNoticeToDateMap(List<InspectionNoticeVO> inspectionNoticeList) {
        // 构建结果映射：键为销售单号|销售单行号|产品编码，值为供方完工日期
        Map<String, Date> resultMap = new HashMap<>();

        for (InspectionNoticeVO noticeVO : inspectionNoticeList) {
            // 获取回仓产品明细列表
            List<InspectionNoticeVO.productDetail> productDetails = noticeVO.get_widget_1694481242685();
            if (productDetails == null || productDetails.isEmpty()) {
                continue; // 跳过无明细的数据
            }

            // 获取当前通知单的供方完工日期（所有明细共享同一日期）
            Date supplyFinishDate = noticeVO.get_widget_1753082933013();

            // 遍历明细，构建映射关系
            for (InspectionNoticeVO.productDetail detail : productDetails) {
                // 提取三个关键字段
                String salesOrderNo = detail.get_widget_1727059443400();
                String salesOrderLineNo = detail.get_widget_1727059443401();
                String productCode = detail.get_widget_1694481242687();

                // 跳过关键字段为空的数据（避免生成无效键）
                if (salesOrderNo == null || salesOrderLineNo == null || productCode == null) {
                    continue;
                }

                // 生成唯一键（销售单号|销售单行号|产品编码）
                String key = String.join("|", salesOrderNo, padWithZeros6(salesOrderLineNo), productCode);

                // 若键已存在，保留先出现的日期（如需保留最新日期，可改为 supplyFinishDate 覆盖）
                resultMap.putIfAbsent(key, supplyFinishDate);
            }
        }

        return resultMap;
    }

    public void selectAndList(Header[] headers,String appId,String entryId){
        // 获取到销售订单数据-YY1_KPI数据。
        List<Lin> consolidatedOrderVOList = new ArrayList<>();
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("app_id", appId);
        parameter.put("entry_id", entryId);

        Map<String, Object> filter = new HashMap<>();
        filter.put("rel", "and");
        Map<String, Object> cond = new HashMap<>();
        cond.put("field", "_widget_1744599627176");
        cond.put("type", "text");
        cond.put("method", "empty");
        List<Map<String, Object>> conds = new ArrayList<>();
        conds.add(cond);
        filter.put("cond", conds);
        parameter.put("filter", filter);

        boolean fale = true;
        String zh = "";
        do {
            if (!zh.isEmpty()) {
                parameter.put("data_id", zh);
            }
            parameter.put("limit", 100);
            String jsonSale = JSONUtil.toJsonStr(parameter);
            JSONObject jdySale = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/app/entry/data/list", headers, jsonSale);
            String data = jdySale.getStr("data");
            JSONArray objects = JSONUtil.parseArray(data);
            List<Lin> list = JSONUtil.toList(objects, Lin.class);
            if (list.size() == 100) {
                zh = list.getLast().get_id();
            } else {
                fale = false;
            }
            consolidatedOrderVOList.addAll(list);
        } while (fale);
        log.info("销售订单数据-YY1_KPI表单数据size：" + consolidatedOrderVOList.size());
        // 判断集合是否有值 有则删除 一次只能删除100条
        if (CollectionUtils.isNotEmpty(consolidatedOrderVOList)) {
            // 提取所有数据ID
            List<String> dataIds = consolidatedOrderVOList.stream()
                    .map(Lin::get_id) // get_id() 是获取数据ID的方法
                    .collect(Collectors.toList());

            int batchSize = 100;
            for (int i = 0; i < dataIds.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, dataIds.size());
                List<String> batchDataIds = dataIds.subList(i, endIndex);

                // 构造删除接口请求参数
                Map<String, Object> deleteParam = new HashMap<>();
                deleteParam.put("app_id", appId);
                deleteParam.put("entry_id", entryId);
                deleteParam.put("data_ids", batchDataIds);

                // 发送删除请求
                String jsonDelete = JSONUtil.toJsonStr(deleteParam);
                JSONObject deleteResponse = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/app/entry/data/batch_delete", headers, jsonDelete);
                // 记录响应日志,判断删除是否成功
                log.info("删除接口响应：{}", deleteResponse);
            }
        }
    }

    // 时间Z转化
    public static String convertToISO8601Format(String dbTime) {
        if(StringUtils.isEmpty(dbTime)){
            return "";
        }
        // 查找秒后的小数部分
        int dotIndex = dbTime.indexOf(".");

        if (dotIndex != -1) {
            // 如果有小数部分，去掉并加上 ".000"
            dbTime = dbTime.substring(0, dotIndex) + ".000";
        } else {
            // 如果没有小数部分，直接加 ".000"
            dbTime = dbTime + ".000";
        }
        // 定义数据库时间格式
        DateTimeFormatter dbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

        // 解析数据库时间
        LocalDateTime localDateTime = LocalDateTime.parse(dbTime, dbFormatter);

        // 将时间减去 8 小时
        LocalDateTime result = localDateTime.minusHours(8);

        // 将结果转换为字符串输出
        return result.format(dbFormatter);
    }

    // 取年月
    public static String getYearMonth(String dbTime) {
        if (dbTime == null || dbTime.isEmpty()) {
            return null;
        }
        // 查找秒后的小数部分
        int dotIndex = dbTime.indexOf(".");

        if (dotIndex != -1) {
            // 如果有小数部分，去掉并加上 ".000"
            dbTime = dbTime.substring(0, dotIndex) + ".000";
        } else {
            // 如果没有小数部分，直接加 ".000"
            dbTime = dbTime + ".000";
        }

        // 定义数据库时间格式
        DateTimeFormatter dbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        LocalDateTime localDateTime = LocalDateTime.parse(dbTime, dbFormatter);

        // 将时间减去 8 小时
        LocalDateTime result = localDateTime.minusHours(8);

        // 获取年份和月份
        return result.format(DateTimeFormatter.ofPattern("yyyy-MM"));
    }

    public List<SalesOrder> getSalesOrderList(){
        List<SalesOrder> salesOrderList = new ArrayList<>();
        Header[] headers = ConnmeUtils.createHeaders();
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("app_id", "667230ad22a8581756b77d52");
        parameter.put("entry_id", "667230b322a8581756b78353");

        Map<String, Object> filter = new HashMap<>();
        filter.put("rel", "and");
        Map<String, Object> cond = new HashMap<>();
        cond.put("field", "flowState");
        cond.put("type", "flowstate");
        cond.put("method", "eq");
        List<Integer> values = new ArrayList<>();
        values.add(1);
        cond.put("value", values);
        List<Map<String, Object>> conds = new ArrayList<>();
        conds.add(cond);
        filter.put("cond", conds);
        parameter.put("filter", filter);

        boolean fale = true;
        String zh = "";
        do {
            if (!zh.isEmpty()) {
                parameter.put("data_id", zh);
            }
            parameter.put("limit", 100);
            String jsonSale = JSONUtil.toJsonStr(parameter);
            JSONObject jdySale = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/app/entry/data/list", headers, jsonSale);
            String data = jdySale.getStr("data");
            JSONArray objects = JSONUtil.parseArray(data);
            List<SalesOrder> list = JSONUtil.toList(objects, SalesOrder.class);
            if (list.size() == 100) {
                zh = list.getLast().get_id();
            } else {
                fale = false;
            }
            salesOrderList.addAll(list);
        } while (fale);
        return salesOrderList;
    }

    public Map<String, Date> getCustomerList(){
        Map<String, Date> customerMap = new HashMap<>();
        List<Customer> customerList = new ArrayList<>();
        Header[] headers = ConnmeUtils.createHeaders();
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("app_id", "66a6f42ff97af74b02d217df");
        parameter.put("entry_id", "66a6f443333584e2c128154f");
        boolean fale = true;
        String zh = "";
        do {
            if (!zh.isEmpty()) {
                parameter.put("data_id", zh);
            }
            parameter.put("limit", 100);
            String jsonSale = JSONUtil.toJsonStr(parameter);
            JSONObject jdySale = ApiClient.sendPostRequest(KeyConstant.Jian_URL + "/v5/app/entry/data/list", headers, jsonSale);
            String data = jdySale.getStr("data");
            JSONArray objects = JSONUtil.parseArray(data);
            List<Customer> list = JSONUtil.toList(objects, Customer.class);
            if (list.size() == 100) {
                zh = list.getLast().get_id();
            } else {
                fale = false;
            }
            customerList.addAll(list);
        } while (fale);

        // 转换 List<Customer> 为 Map<String, Date>
        for (Customer customer : customerList) {
            String customerCode = customer.get_widget_1722305048887();
            Date createDate = customer.get_widget_1733204191654();

            // 处理空值（跳过无效数据）
            if (customerCode != null && createDate != null) {
                customerMap.put(customerCode, createDate);
            }
        }
        return customerMap;
    }

    /**
     * 提取JSON格式数据中的name字段（适配String/Object类型输入）
     * @param jsonData 原始数据（可能是JSON字符串、Object对象）
     * @return 提取的name，为空或解析失败返回null
     */
    private String extractNameFromJson(Object jsonData) {
        // 1. 空值直接返回null
        if (jsonData == null) {
            return null;
        }

        try {
            // 2. 转为JSON字符串（兼容String和Object类型）
            String jsonStr = jsonData instanceof String
                    ? (String) jsonData
                    : JSONUtil.toJsonStr(jsonData);

            // 3. 解析JSON并提取name字段
            JSONObject jsonObj = JSONUtil.parseObj(jsonStr);
            return jsonObj.getStr("name"); // 没有name字段时返回null
        } catch (Exception e) {
            log.error("解析name字段失败，原始数据：{}", jsonData, e);
            return null; // 异常兜底返回null
        }
    }

    /**
     * 采购订单-检验订单数据 p 采购订单准交率
     * @return
     */
    @GetMapping("orderDeliveryRate")
    public String orderDeliveryRate() {
        Header[] headers = ConnmeUtils.createHeaders();
        String appId = "67f8aa2676b9b3942c49035f";
        String entryId = "69045b685adae1eceddc2b73";
        List<Map<String, Object>> mapList = new ArrayList<>();

        // 1. 核心数据获取
        List<PurchaseOrderList> purchaseDataList = yy1KpiMapper.selectPurchaseOrderRate();
        List<InspectionData> inspectionDataList = fetchJianDaoYunData(
                headers, "64a7b7416bbd930007630ed5", "64a7b81afc35ba00082dbcad", InspectionData.class
        );
        List<InspectedVO> salesDataList = fetchJianDaoYunData(
                headers, "67f8aa2676b9b3942c49035f", "68fae026d12c1eb2a5a17434", InspectedVO.class
        );

        // 批量删除简道云原有数据
        selectAndList(headers, appId, entryId);

        // 2. 构建索引（优化匹配效率）
        // 检验数据索引：采购单号+采购行号+物料号 → 检验数据
        Map<String, InspectionData> inspectionIndex = inspectionDataList.stream()
                .filter(insp -> insp.getTotal_qty() > 0) // 仅保留有质检数量（已交货）的记录
                .collect(Collectors.toMap(
                        insp -> generateKey(insp.getPurchasing_no(), padWithZeros(insp.getPurchasing_hang()), insp.getItem_no()),
                        insp -> insp,
                        (existing, replacement) -> existing
                ));

        // 销售-交货数据索引：销售单号+销售行号+物料号 → 交货数据
        Map<String, InspectedVO> salesDeliveryIndex = salesDataList.stream()
                .filter(vo -> "全部出货".equals(vo.get_widget_1752125855356())) // 仅保留行交货状态为“全部出货”的记录
                .collect(Collectors.toMap(
                        vo -> generateKey(
                                vo.get_widget_1743997558327(), // 销售文档
                                vo.get_widget_1743997558328(), // 销售文档项目
                                vo.get_widget_1743997558336()  // 物料
                        ),
                        vo -> vo,
                        (existing, replacement) -> existing
                ));

        // 3. 遍历采购订单，逐一处理
        for (PurchaseOrderList purchase : purchaseDataList) {
            OrderDeliveryRateCC vo = new OrderDeliveryRateCC();
            // 3.1 基础字段赋值（从采购订单直接映射）
            vo.set_widget_1761893223996(purchase.getPurchaseOrder()); // 采购订单号
            vo.set_widget_1761893223997(purchase.getPurchaseOrderItem()); // 采购行号
            vo.set_widget_1761893223998(purchase.getMaterial()); // 物料编码
            vo.set_widget_1761893223999(purchase.getScheduleLineDeliveryDate()); // 采购计划交货日期
            vo.set_widget_1761893224003(purchase.getAddressSearchTerm1()); // 供应商名称（简称）
            vo.set_widget_1761893224004(purchase.getPurchasingGroupName()); // 采购员（采购组名称）

            // 3.2 新增字段赋值（采购订单直接提取）
            vo.set_widget_1762341021132(purchase.getOrderQuantity()); // 采购数量（订单数量）
            vo.set_widget_1762341021133(purchase.getDeliveredQuantity() != null ? purchase.getDeliveredQuantity().toString() : "0"); // 收货数量
            vo.set_widget_1762341021134(safeParseBigDecimal(purchase.getConditionAmount())); // 采购金额
            vo.set_widget_1762341021135(purchase.getDeliveredAmount() != null ? purchase.getDeliveredAmount() : BigDecimal.ZERO); // 已收货金额
            // 采购订单制单日期（String转Date，格式假设为yyyy-MM-dd）
            vo.set_widget_1762418663867(safeParseDate(purchase.getPurchaseOrderDate(), "yyyy-MM-dd"));

            // 3.3 匹配检验数据（核心逻辑1：有质检数量→已交货）
            String inspectionKey = generateKey(
                    purchase.getPurchaseOrder(),
                    purchase.getPurchaseOrderItem(),
                    purchase.getMaterial()
            );
            InspectionData matchedInsp = inspectionIndex.get(inspectionKey);
            Date inspectionDate = null;
            Integer deliveryDays = null;
            String isOnTime = "未检验"; // 默认未检验
            BigDecimal productionDays = null; // 供方生产天数

            if (matchedInsp != null) {
                // 3.3.1 检验日期赋值（String转Date）
                inspectionDate = safeParseDate(matchedInsp.getDate_of_inspection(), "yyyy-MM-dd");
                vo.set_widget_1761893224000(inspectionDate); // 来货检验日期
                vo.set_widget_1762344704394(String.valueOf(matchedInsp.getTotal_qty())); // 采购订单质检数量（检验数据的total_qty）

                // 3.3.2 计算供方延误天数（检验日期 - 计划交货日期）
                Date planDate = safeParseDate(purchase.getScheduleLineDeliveryDate(), "yyyy-MM-dd");
                if (inspectionDate != null && planDate != null) {
                    long timeDiff = inspectionDate.getTime() - planDate.getTime();
                    deliveryDays = (int) (timeDiff / (1000 * 60 * 60 * 24));
                    isOnTime = deliveryDays <= 0 ? "及时交货" : "不及时交货"; // 检验数据匹配的准交状态
                }

                // 3.3.3 计算供方生产天数（检验日期 - 采购制单日期）
                Date orderCreateDate = safeParseDate(purchase.getPurchaseOrderDate(), "yyyy-MM-dd");
                if (inspectionDate != null && orderCreateDate != null) {
                    long productionDiff = inspectionDate.getTime() - orderCreateDate.getTime();
                    productionDays = BigDecimal.valueOf(productionDiff / (1000 * 60 * 60 * 24));
                }
            }

            // 3.4 无检验数据时，匹配销售-交货数据（核心逻辑2：行交货状态=全部出货）
            if (matchedInsp == null) {
                // 采购订单中的销售订单信息（用于匹配）
                String salesOrder = purchase.getSalesOrder();
                String salesOrderItem = purchase.getSalesOrderItem();
                String material = purchase.getMaterial();

                if (salesOrder != null && salesOrderItem != null && material != null) {
                    String salesKey = generateKey(salesOrder, salesOrderItem, material);
                    InspectedVO matchedSales = salesDeliveryIndex.get(salesKey);

                    if (matchedSales != null) {
                        Date latestDeliveryTime = matchedSales.get_widget_1752128631870(); // 最晚交货时间
                        Date planDate = safeParseDate(purchase.getScheduleLineDeliveryDate(), "yyyy-MM-dd");

                        if (latestDeliveryTime != null && planDate != null) {
                            long timeDiff = latestDeliveryTime.getTime() - planDate.getTime();
                            deliveryDays = (int) (timeDiff / (1000 * 60 * 60 * 24));
                            // 销售交货匹配的准交状态，加#区分
                            isOnTime = deliveryDays <= 0 ? "及时交货#销售匹配" : "不及时交货#销售匹配";
                        }
                    }
                }
            }

            // 3.5 赋值最终计算结果
            vo.set_widget_1761893224001(deliveryDays); // 供方延误天数
            vo.set_widget_1762418663866(productionDays != null ? productionDays.toString() : ""); // 供方生产天数
            vo.set_widget_1761893224002(isOnTime); // 是否准交（含区分标识）

            // 3.6 转为Map加入批量插入列表
            mapList.add(ConnmeUtils.convertEntityToMap(vo));
        }

        // 4. 批量存入简道云
        ConnmeUtils.batchAddList(headers, appId, entryId, mapList);

        return "success";
    }

    // 工具方法：安全解析BigDecimal（处理空值/非数字）
    private BigDecimal safeParseBigDecimal(String value) {
        if (value == null || value.trim().isEmpty()) {
            return BigDecimal.ZERO;
        }
        try {
            return new BigDecimal(value.trim());
        } catch (NumberFormatException e) {
            log.warn("解析BigDecimal失败，值：{}，默认返回0", value);
            return BigDecimal.ZERO;
        }
    }

    // 工具方法：安全解析Date（处理空值/格式不匹配）
    private Date safeParseDate(String dateStr, String format) {
        if (dateStr == null || dateStr.trim().isEmpty()) {
            return null;
        }
        try {
            return new SimpleDateFormat(format).parse(dateStr.trim());
        } catch (ParseException e) {
            log.warn("解析日期失败，值：{}，格式：{}，返回null", dateStr, format);
            return null;
        } catch (java.text.ParseException e) {
            throw new RuntimeException(e);
        }
    }
}
